import os
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Rescaling, Conv2D, MaxPooling2D, Dense, Flatten, Dropout, BatchNormalization
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.optimizers import Adam
from sklearn.metrics import confusion_matrix, precision_score, recall_score, accuracy_score, f1_score
# location path of the datasets
train_dir = "/Users/preslav/Downloads/cw_cop528/imageset/train"
test_dir = "/Users/preslav/Downloads/cw_cop528/imageset/val"
# setting a common standard for the pixel values, to fall in
# setting a validation and training split
train_data = ImageDataGenerator(rescale=1./255,
validation_split=0.2)
val_data = ImageDataGenerator(rescale=1/255,
validation_split=0.2)
test_data = ImageDataGenerator(rescale=1./255)
# importing the data batches and setting their properties
train_batches = train_data.flow_from_directory(directory = train_dir,
target_size = (224, 224),
subset = "training",
batch_size = 32,
seed = 2)
validation_batches = val_data.flow_from_directory(directory = train_dir,
target_size = (224, 224),
subset = "validation",
batch_size = 32,
seed = 2)
test_batches = test_data.flow_from_directory(directory = test_dir,
target_size = (224, 224),
batch_size = 32,
shuffle = False)
Found 7578 images belonging to 10 classes. Found 1891 images belonging to 10 classes. Found 3925 images belonging to 10 classes.
# import of the class labels names and their total number
class_names = list(train_batches.class_indices.keys())
num_classes = len(class_names)
print(class_names)
print(num_classes)
['building', 'dog', 'fish', 'gas_station', 'golf', 'musician', 'parachute', 'radio', 'saw', 'vehicle'] 10
# importing a batch of images and labels
img, lbl = next(train_batches)
# plotting 9 images and their respective class labels
plt.figure(figsize = (12, 12))
for i in range(9):
class_index = np.argmax(lbl[i])
plt.subplot(3, 3, i + 1)
plt.imshow(img[i])
plt.title(class_names[class_index])
plt.axis("off")
plt.tight_layout()
plt.show()
# setting the model's architecture
model_adapted = Sequential([
Conv2D(16, (3,3), 1, activation="relu"),
BatchNormalization(),
MaxPooling2D(),
Conv2D(32, (3,3), 1, activation="relu"),
BatchNormalization(),
Dropout(0.25),
Conv2D(32, (3,3), 1, activation="relu"),
BatchNormalization(),
Conv2D(32, (3,3), 1, activation="relu"),
BatchNormalization(),
MaxPooling2D(),
Conv2D(32, (3,3), 1, activation="relu"),
BatchNormalization(),
Dropout(0.25),
Conv2D(32, (3,3), 1, activation="relu"),
BatchNormalization(),
MaxPooling2D(),
Flatten(),
Dense(256, activation="relu"),
BatchNormalization(),
Dropout(0.5),
Dense(num_classes, activation="softmax")
])
Metal device set to: Apple M2
2023-03-17 11:12:37.030541: I tensorflow/core/common_runtime/pluggable_device/pluggable_device_factory.cc:305] Could not identify NUMA node of platform GPU ID 0, defaulting to 0. Your kernel may not have been built with NUMA support. 2023-03-17 11:12:37.030659: I tensorflow/core/common_runtime/pluggable_device/pluggable_device_factory.cc:271] Created TensorFlow device (/job:localhost/replica:0/task:0/device:GPU:0 with 0 MB memory) -> physical PluggableDevice (device: 0, name: METAL, pci bus id: <undefined>)
# setting the model's loss function, gradient descnet optimizer and evaluation metrics
model_adapted.compile(optimizer = "adam", loss = "categorical_crossentropy", metrics = ["accuracy"])
# performing training of the model with the training batches and validation batches
epochs = 20
history_adapted= model_adapted.fit(train_batches,
validation_data = validation_batches,
epochs = epochs)
Epoch 1/20
2023-03-17 11:12:38.106302: W tensorflow/core/platform/profile_utils/cpu_utils.cc:128] Failed to get CPU frequency: 0 Hz 2023-03-17 11:12:38.534401: I tensorflow/core/grappler/optimizers/custom_graph_optimizer_registry.cc:113] Plugin optimizer for device_type GPU is enabled.
237/237 [==============================] - ETA: 0s - loss: 1.8543 - accuracy: 0.4216
2023-03-17 11:13:13.874044: I tensorflow/core/grappler/optimizers/custom_graph_optimizer_registry.cc:113] Plugin optimizer for device_type GPU is enabled.
237/237 [==============================] - 39s 151ms/step - loss: 1.8543 - accuracy: 0.4216 - val_loss: 5.3740 - val_accuracy: 0.1666 Epoch 2/20 237/237 [==============================] - 33s 140ms/step - loss: 1.4165 - accuracy: 0.5449 - val_loss: 2.7775 - val_accuracy: 0.2877 Epoch 3/20 237/237 [==============================] - 33s 140ms/step - loss: 1.1051 - accuracy: 0.6411 - val_loss: 2.0318 - val_accuracy: 0.4759 Epoch 4/20 237/237 [==============================] - 33s 140ms/step - loss: 0.9611 - accuracy: 0.6840 - val_loss: 2.9596 - val_accuracy: 0.3876 Epoch 5/20 237/237 [==============================] - 33s 140ms/step - loss: 0.8340 - accuracy: 0.7245 - val_loss: 1.2507 - val_accuracy: 0.6251 Epoch 6/20 237/237 [==============================] - 33s 140ms/step - loss: 0.6849 - accuracy: 0.7703 - val_loss: 1.4563 - val_accuracy: 0.5653 Epoch 7/20 237/237 [==============================] - 33s 140ms/step - loss: 0.5766 - accuracy: 0.8127 - val_loss: 4.2766 - val_accuracy: 0.2845 Epoch 8/20 237/237 [==============================] - 33s 140ms/step - loss: 0.6163 - accuracy: 0.7895 - val_loss: 2.3085 - val_accuracy: 0.4564 Epoch 9/20 237/237 [==============================] - 33s 140ms/step - loss: 0.3898 - accuracy: 0.8769 - val_loss: 1.3975 - val_accuracy: 0.6055 Epoch 10/20 237/237 [==============================] - 33s 140ms/step - loss: 0.2792 - accuracy: 0.9111 - val_loss: 1.6463 - val_accuracy: 0.5843 Epoch 11/20 237/237 [==============================] - 33s 140ms/step - loss: 0.2146 - accuracy: 0.9307 - val_loss: 1.9894 - val_accuracy: 0.5463 Epoch 12/20 237/237 [==============================] - 33s 140ms/step - loss: 0.1876 - accuracy: 0.9381 - val_loss: 1.5941 - val_accuracy: 0.6192 Epoch 13/20 237/237 [==============================] - 33s 140ms/step - loss: 0.1719 - accuracy: 0.9447 - val_loss: 1.4847 - val_accuracy: 0.6330 Epoch 14/20 237/237 [==============================] - 33s 140ms/step - loss: 0.1570 - accuracy: 0.9496 - val_loss: 1.9661 - val_accuracy: 0.5468 Epoch 15/20 237/237 [==============================] - 33s 140ms/step - loss: 0.1188 - accuracy: 0.9629 - val_loss: 2.0424 - val_accuracy: 0.5764 Epoch 16/20 237/237 [==============================] - 33s 140ms/step - loss: 0.1113 - accuracy: 0.9656 - val_loss: 1.6883 - val_accuracy: 0.6282 Epoch 17/20 237/237 [==============================] - 33s 140ms/step - loss: 0.0890 - accuracy: 0.9710 - val_loss: 1.9403 - val_accuracy: 0.5986 Epoch 18/20 237/237 [==============================] - 33s 140ms/step - loss: 0.1366 - accuracy: 0.9542 - val_loss: 1.8291 - val_accuracy: 0.6013 Epoch 19/20 237/237 [==============================] - 33s 141ms/step - loss: 0.0963 - accuracy: 0.9681 - val_loss: 1.9379 - val_accuracy: 0.5838 Epoch 20/20 237/237 [==============================] - 33s 140ms/step - loss: 0.0861 - accuracy: 0.9715 - val_loss: 2.9115 - val_accuracy: 0.5431
# getting the model's summary
model_adapted.summary()
Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
conv2d (Conv2D) (None, None, None, 16) 448
batch_normalization (BatchN (None, None, None, 16) 64
ormalization)
max_pooling2d (MaxPooling2D (None, None, None, 16) 0
)
conv2d_1 (Conv2D) (None, None, None, 32) 4640
batch_normalization_1 (Batc (None, None, None, 32) 128
hNormalization)
dropout (Dropout) (None, None, None, 32) 0
conv2d_2 (Conv2D) (None, None, None, 32) 9248
batch_normalization_2 (Batc (None, None, None, 32) 128
hNormalization)
conv2d_3 (Conv2D) (None, None, None, 32) 9248
batch_normalization_3 (Batc (None, None, None, 32) 128
hNormalization)
max_pooling2d_1 (MaxPooling (None, None, None, 32) 0
2D)
conv2d_4 (Conv2D) (None, None, None, 32) 9248
batch_normalization_4 (Batc (None, None, None, 32) 128
hNormalization)
dropout_1 (Dropout) (None, None, None, 32) 0
conv2d_5 (Conv2D) (None, None, None, 32) 9248
batch_normalization_5 (Batc (None, None, None, 32) 128
hNormalization)
max_pooling2d_2 (MaxPooling (None, None, None, 32) 0
2D)
flatten (Flatten) (None, None) 0
dense (Dense) (None, 256) 4718848
batch_normalization_6 (Batc (None, 256) 1024
hNormalization)
dropout_2 (Dropout) (None, 256) 0
dense_1 (Dense) (None, 10) 2570
=================================================================
Total params: 4,765,226
Trainable params: 4,764,362
Non-trainable params: 864
_________________________________________________________________
# Graphical evaluation of training performance
acc = history_adapted.history['accuracy']
val_acc = history_adapted.history['val_accuracy']
loss = history_adapted.history['loss']
val_loss = history_adapted.history['val_loss']
epochs_range = range(epochs)
plt.figure(figsize=(11, 8))
plt.subplots_adjust(hspace = .3)
plt.subplot(2, 1, 1)
plt.plot(epochs_range, acc, label = 'Training Accuracy', color = "orange")
plt.plot(epochs_range, val_acc, label = 'Validation Accuracy', color = "blue")
plt.legend(loc = 'best')
plt.xlabel('Epochs')
plt.title('Training and Validation Accuracy', size = 13)
plt.subplot(2, 1, 2)
plt.plot(epochs_range, loss, label = 'Training Loss', color = "orange")
plt.plot(epochs_range, val_loss, label = 'Validation Loss', color = "blue")
plt.legend(loc = 'best')
plt.title('Training and Validation Loss', size = 13)
plt.xlabel('Epochs')
plt.suptitle("Base Model's Architecture Updated", size=15)
plt.show()
# test loss and accuracy measurments
test_loss, test_acc = model_adapted.evaluate(test_batches)
print('Test loss:', test_loss)
print('Test accuracy:', test_acc)
123/123 [==============================] - 7s 60ms/step - loss: 3.0033 - accuracy: 0.5473 Test loss: 3.0032505989074707 Test accuracy: 0.5472611784934998
# getting prediction labales by running the softmax results in argmax
test_labels = test_batches.classes
y_pred = model_adapted.predict(test_batches)
predicted_lables = np.argmax(y_pred, axis = 1)
cm = confusion_matrix(test_labels, predicted_lables)
1/123 [..............................] - ETA: 24s
2023-03-17 11:23:58.123339: I tensorflow/core/grappler/optimizers/custom_graph_optimizer_registry.cc:113] Plugin optimizer for device_type GPU is enabled.
123/123 [==============================] - 7s 57ms/step
# dataframe containing the confussion matrix
cfm = pd.DataFrame(cm, index = class_names, columns = class_names)
# plotting the conffusion matrix
sns.heatmap(cfm, annot=True, fmt='d', cmap='Purples')
plt.xlabel('Predicted Label')
plt.ylabel('True Label')
plt.xticks(rotation=78)
plt.title("Base Model's Architecture Updated", size=15)
plt.show()
print("Preicision score:", precision_score(test_labels, predicted_lables, average="weighted"))
print("Recall score:", recall_score(test_labels, predicted_lables, average = "weighted"))
print("F1_score:", f1_score(test_labels, predicted_lables, average = "weighted"))
Preicision score: 0.5987872636790471 Recall score: 0.5472611464968152 F1_score: 0.5229290750405292
# importing the test datest again, so that this time images can be shuffled
# so that displayed images are not ordered in the same way as in the dataset
# and variety of classes can be examined
test_data_shuffled = tf.keras.utils.image_dataset_from_directory(test_dir, shuffle = True, seed = 247)
Found 3925 files belonging to 10 classes.
def right_format_image(pic):
'''
This function returns a
reshaped image into 224x224
format in terms of height and
width.
Further it normalizes the
pixel values within the range
of [0, 1].
'''
img_size = (224, 224)
image = tf.image.resize(pic, img_size)
image_expanded = np.expand_dims(image, axis=0)
image_copy = np.copy(image_expanded)
normalized = image_copy/255.
return normalized
def data_iterator(data):
'''
This function returns as arrays the
components of a batch.
'''
iterator = data.as_numpy_iterator()
batch = iterator.next()
return batch
# plotting images from the test dataset, with their actual and predicted from the model labels
predicted_batch = data_iterator(test_data_shuffled)
plt.figure(figsize=(12, 12))
plt.subplots_adjust(hspace = .1, wspace=.3)
plt.suptitle("Base Model's Architecture Updated", size = 20)
for i in range(9):
image, label = predicted_batch[0][i], predicted_batch[1][i]
predictions = model_adapted.predict(right_format_image(image))
prediction_label = class_names[predictions.argmax()]
ax = plt.subplot(3, 3, i + 1)
plt.imshow(image.astype(np.uint8))
plt.title("Actual label:{};\nPredicted label:{}".format(class_names[label],
class_names[predictions.argmax()]), size = 9)
plt.axis("off")
2023-03-17 11:24:06.020269: I tensorflow/core/grappler/optimizers/custom_graph_optimizer_registry.cc:113] Plugin optimizer for device_type GPU is enabled.
1/1 [==============================] - 0s 442ms/step 1/1 [==============================] - 0s 8ms/step 1/1 [==============================] - 0s 8ms/step 1/1 [==============================] - 0s 8ms/step 1/1 [==============================] - 0s 8ms/step 1/1 [==============================] - 0s 8ms/step 1/1 [==============================] - 0s 9ms/step 1/1 [==============================] - 0s 8ms/step 1/1 [==============================] - 0s 8ms/step